﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Sql;
using System.Data.SqlClient;

namespace Inference
{
    public partial class Is_aForm : Form
    {
        public Is_aForm(int _frameID, TaleEntities _tale, SqlConnection _conn)
        {
            InitializeComponent();
            FrameID = _frameID;
            tale = new TaleEntities();//_tale;
            conn = _conn;
        }

        public int Is_aID = -1;
        public bool IfLinkChanged = false;
        int FrameID = -1, ParentSlotsCount = -1; TaleEntities tale; SqlConnection conn;

        private void Is_aForm_Load(object sender, EventArgs e)
        {
            this.cmb_framename.SelectedIndexChanged -= new System.EventHandler(this.comboBox1_SelectedIndexChanged);
            // load frame names            
            var r = from d in tale.Domains
                    join dv in tale.DomainsValues on d.ID equals dv.DomID
                    join ddvv in tale.DValues on dv.Value equals ddvv.ID
                    where d.ID == 1 || d.ID == 7
                    orderby d.ID descending
                    select ddvv;
            cmb_framename.Items.Clear();
            foreach (Inference.DValues dom_v in r)
            {
                cmb_framename.Items.Add(dom_v.Value);
            }
            var child_frame = tale.Frame.Where(v => v.ID == FrameID);
            int is_a = -1;
            try
            {
                is_a = (int)child_frame.First().Is_a;
            }
            catch { }
            if (is_a == -1)
            {
                if (cmb_framename.Items.Count >0)
                    cmb_framename.SelectedIndex = 0;
                else
                    cmb_framename.SelectedIndex = -1;
            }
            else
            {
                var isa_name = tale.Frame.Where(v => v.ID == is_a);
                if (isa_name != null)
                {
                    cmb_framename.SelectedIndex = cmb_framename.Items.IndexOf(isa_name.First().Name);
                }
            }
            this.cmb_framename.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
        }


        #region copying
        private void CreateDown(int slotID)
        {
            TaleEntities tale1 = new TaleEntities();
            var slot = tale1.Slot.Where(v => v.ID == slotID).First();
            var children = CheckIf.ChildrenOf(slot.Frame.Name, true, tale1);
            foreach (Inference.Frame fr in children)
            {
                try
                {
                    Slot new_slot = new Slot();
                    new_slot.Name = slot.Name;
                    new_slot.Number = slot.Number;
                    new_slot.Inheritance = slot.Inheritance;
                    new_slot.DefaultValue = slot.DefaultValue;
                    new_slot.Domain = slot.Domain;
                    new_slot.DomainType = slot.DomainType;
                    new_slot.FrameID = fr.ID;
                    new_slot.Question = "Каково значение слота " + slot.Name + " из фрейма " + fr.Name + "?";
                    tale1.Slot.AddObject(new_slot);
                    tale1.SaveChanges();
                    //ReindexSlotsAdd(new_slot.ID, fr.ID);
                }
                catch
                {
                    MessageBox.Show("Ошибка при создании слота!", "Ошибка");
                }
            }
        }

        private int GetLastSlotID()
        {
            int temp = -1;
            try
            {
                temp = tale.Slot.Max(v => v.ID);
            }
            catch { temp = -1; }
            return temp;
            //SqlCommand get_slot_id = new SqlCommand("", conn);
            //get_slot_id.CommandText = "select max(ID) from Slot";
            //SqlDataReader sread = get_slot_id.ExecuteReader();
            //while (sread.Read())
            //    temp = sread.GetInt32(0);
            //sread.Close();            
        }

        private void CreateParentSlots(int parent_id)
        {
            SqlCommand create_slot;            
            var new_is_a = //tale.Slot.Where(v => v.FrameID == parent_id).OrderBy(v => v.Number);
                     from s in tale.Slot where s.FrameID == parent_id orderby s.Number ascending select s;
            Frame frame = tale.Frame.Where(v => v.ID == FrameID).First();
            int i = 0;
            foreach (Inference.Slot par_sl in new_is_a)
            {
                TaleEntities tale1 = new TaleEntities();
                Slot new_slot = new Slot();
                new_slot.Name = par_sl.Name;
                new_slot.Number = par_sl.Number;
                new_slot.AllowNull = par_sl.AllowNull;
                new_slot.Inheritance = par_sl.Inheritance;
                new_slot.DefaultValue = par_sl.DefaultValue;
                new_slot.Domain = par_sl.Domain;
                new_slot.DomainType = par_sl.DomainType;
                new_slot.FrameID = FrameID;
                new_slot.Question = "Каково значение слота " + par_sl.Name + " из фрейма " + frame.Name + "?";
                tale1.Slot.AddObject(new_slot);
                tale1.SaveChanges();

                //create_slot = new SqlCommand("", conn);
                //create_slot.CommandText = "insert into Slot (Name,Domain,DefaultValue, AllowNull, " +
                //"FrameID, Question,Number, Inheritance) values (\'" +
                //par_sl.Name + "\', " +
                //par_sl.Domain + ", " +
                //(par_sl.DefaultValue == null ? "NULL" : par_sl.DefaultValue.ToString()) + ", " +
                //(par_sl.AllowNull ? "1" : "0") + ", " +
                //FrameID.ToString() + ", " +
                //"'', " + /*par_sl.Number*/i.ToString() + ", " +
                //par_sl.Inheritance +
                //")";
                //create_slot.ExecuteNonQuery();
             
                i++;
            }
            var slots = tale.Slot.Where(v=>v.FrameID == frame.ID);
            foreach (Inference.Slot sl in slots)
            {                
                CreateDown(sl.ID);
            }
            ParentSlotsCount = i;
        }

        string GetRoot(int FrameID)
        {
            Frame fr;
            do
            {
                fr = tale.Frame.Where(f => f.ID == FrameID).First();
                if (fr.Is_a.HasValue)
                    FrameID = fr.Is_a.Value;
                else
                    FrameID = 0;
            }
            while (FrameID != 0);
            return fr.Name;
        }

        private void ReindexSlots(Inference.Frame frame, bool next_ex)   // numbers
        {
            TaleEntities tale = new TaleEntities();
            var slots = tale.Slot.Where(v => v.FrameID == frame.ID).OrderBy(v => v.Number);
            int i = ParentSlotsCount;
            Inference.Slot next_slot = null;
            foreach (Inference.Slot sl in slots)
            {
                try
                {
                    if (!CheckIf.SlotIsInherited(sl.Name, frame.Name))
                    {
                        sl.Number = i;
                        tale.SaveChanges();
                        i++;
                    }
                    if (next_ex && sl.Name.ToString().ToLower() == "next")
                        next_slot = sl;
                }
                catch { }

            }
            if (next_ex && next_slot != null)
            {
                next_slot.Number = i;
                tale.SaveChanges();
            }
        }

        private void DeleteSlot(int slotID)
        {
            int success = 0;
            if (slotID >= 0)
            {
                SqlCommand get_facts, delete_slot;
                get_facts = new SqlCommand("", conn);
                get_facts.CommandText = "select * from Fact where SlotID=" + slotID;
                SqlDataAdapter sadapt = new SqlDataAdapter(get_facts);
                DataTable df = new DataTable();
                sadapt.Fill(df);
                for (int i = 0; i < df.Rows.Count; i++)
                //foreach (Inference.Fact sf in slot_facts)
                {
                    try
                    {
                        delete_slot = new SqlCommand("", conn);
                        delete_slot.CommandText = "delete from ProductionFact where FactID=" + df.Rows[i].ItemArray[0]; //sf.ID;
                        delete_slot.ExecuteNonQuery();
                    }
                    catch { success = -1; }
                }
                for (int i = 0; i < df.Rows.Count; i++)
                //foreach (Inference.Fact sf in slot_facts)
                {
                    try
                    {
                        delete_slot = new SqlCommand("", conn);
                        delete_slot.CommandText = "delete from Fact where ID=" + df.Rows[i].ItemArray[0]; //sf.ID;
                        delete_slot.ExecuteNonQuery();
                    }
                    catch { success = -1; }
                }
                try
                {
                    delete_slot = new SqlCommand("", conn);
                    delete_slot.CommandText = "delete from Slot where ID=" + slotID;
                    delete_slot.ExecuteNonQuery();
                }
                catch { success = -1; }
            }
        }

        private int RecursDeleteSlot(int slotID, string frameName)
        {
            int success = 0;
            if (slotID >= 0)
            {
                string slot_name = tale.Slot.Where(v => v.ID == slotID).First().Name;
                //DeleteSlot(slotID);
                //List<Inference.Frame> children = Inference.CheckIf.ChildrenOf(frameName, true, tale);
                List<Slot> deleted_slots =  CheckIf.SlotsNamedLike(slot_name, frameName, tale);
                for (int i = 0; i < deleted_slots.Count; i++)
                {
                    try
                    {
                        SlotFrameFuncs.DeleteSlot(deleted_slots[i].ID, tale);
                    }
                    catch { success = -1; }
                }
                //for (int j = 0; j < children.Count; j++)
                //{
                //    var slot = tale.Slot.Where(v => v.Name == slot_name && v.FrameID == children[j].ID);
                //    if (slot.Count()>0)
                //    {
                //        int slot_id = slot.First().ID;
                //        DeleteSlot(slot_id);
                //    }
                //}
                return success;
            }
            return success;
        }

        string dn = "", dna = "";
        Inference.frmMain frm = (Inference.frmMain)Application.OpenForms["frmMain"];
        private void DeleteFrameFromDomain(string frameName)
        {
            Domains dom = tale.Domains.Where(d => d.Name == dn).First();
            DomainsValues domval = dom.DomainsValues.Where(d => d.DValues.Value == frameName).First();
            DValues dv1 = domval.DValues;
            tale.DeleteObject(domval);
            tale.DeleteObject(dv1);
            tale.SaveChanges();
            frm.RefreshDomainNodes(dom, dn);
        }

        private void AddFrameToDomain(string frameName)
        {
            Domains d = tale.Domains.Where(v => v.Name == dna).First();
            DomainsValues domval = new DomainsValues();
            domval.DValues = new DValues();
            domval.DValues.Value = frameName;
            d.DomainsValues.Add(domval);
            tale.SaveChanges();
            frm.RefreshDomainNodes(d, dna);
        }
        #endregion

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cmb_framename.SelectedIndex != -1 && cmb_framename.Text.Trim() != "")
            {
                var frame = tale.Frame.Where(v => v.ID == FrameID).First();
                if (!CheckIf.LinkISACouldBeCreated((string)frame.Name, cmb_framename.Text))
                    MessageBox.Show("Связь Is_a не может быть проведена к данному фрейму,\n так как в случае " +
                                "ее проведения образуется направленный цикл по связи Is_a!", "Ошибка", MessageBoxButtons.OKCancel);

            }
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {            
                var frame1 = tale.Frame.Where(v => v.ID == FrameID);
                var new_is_a1 = tale.Frame.Where(v => v.Name == cmb_framename.Text);
                if (frame1 != null && new_is_a1 != null)
                {
                    var frame = frame1.First();
                    var new_is_a = new_is_a1.First();
                    if (frame.Is_a != new_is_a.ID)
                    {
                        string str = "Вы действительно хотите изменить связь Is_a? \n При изменении все" +
                            " слоты, пронаследованные от старого родителя будут удалены из фрейма," +
                            " а от нового - добавлены.";
                        DialogResult dr = MessageBox.Show(str, "Внимание", MessageBoxButtons.OKCancel);
                        if (dr == DialogResult.OK)
                        {
                            var child_slots = from s in tale.Slot where (s.FrameID == FrameID) select s;
                            foreach (var sl in child_slots)
                                if (CheckIf.SlotIsInherited(sl.Name, frame.Name))
                                    RecursDeleteSlot(sl.ID, frame.Name);
                            if (new_is_a != null)
                            {
                                string old_root_name = GetRoot(FrameID).ToLower(), new_root_name = GetRoot(new_is_a.ID).ToLower();
                                CreateParentSlots(new_is_a.ID);

                                if (old_root_name == "ситуация" && new_root_name != "ситуация")
                                {
                                    dn = "Имена фреймов-ситуаций";
                                    dna = "Имена фреймов-сущностей";
                                    ReindexSlots(frame, false);
                                }
                                else if (old_root_name != "ситуация" && new_root_name == "ситуация")
                                {
                                    dn = "Имена фреймов-сущностей";
                                    dna = "Имена фреймов-ситуаций";
                                    // make 'next' last
                                    ReindexSlots(frame, true);
                                }
                                if (old_root_name != new_root_name)
                                {
                                    DeleteFrameFromDomain(frame.Name);
                                    AddFrameToDomain(frame.Name);
                                }
                                frame.Is_a = new_is_a.ID;
                                tale.SaveChanges();
                                IfLinkChanged = true;
                                this.DialogResult = DialogResult.OK;
                                this.Close();
                            }
                        }
                    }
                    else
                    {
                        IfLinkChanged = false;
                        this.DialogResult = DialogResult.OK;
                        this.Close();
                    }
                }
                else
                {
                    MessageBox.Show("Ошибка изменения связи!", "Ошибка");
               }
            
        }

        private void btn_cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
